package com.wan.net.handler.protobuf;

import cn.hutool.core.util.ClassUtil;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Message;
import com.google.protobuf.Parser;
import com.wan.net.core.packet.Packet;
import io.netty.channel.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;

/**
 * 服务器消息处理
 * @param <Request>
 * @param <Response>
 */
public abstract class ProtobufServerProcessor<Request extends Message,Response extends Message> implements Processor {
    protected final Logger log = LoggerFactory.getLogger(getClass());
    private final int cmd;
    private final Parser<Request> parser;

    public ProtobufServerProcessor() {
        Class<?> requestClass =  ClassUtil.getTypeArgument(getClass(), 0);
        try {
            Method method = requestClass.getMethod("parse");
            parser = (Parser<Request>) method.invoke(null);
        } catch (Exception e) {
            log.error("load handler error-->" + requestClass);
            throw new RuntimeException(e.getMessage(), e);
        }
        // 直接在请求和类型响应类名命名上通过下划线约定协议id，例如Login_request_100请求登录cmd就是100
        String requestClassName = requestClass.getSimpleName().toLowerCase();
        final String[] splitData = requestClassName.split("_");
        try {
            cmd = Integer.parseInt(splitData[splitData.length - 1]);//消息ID
        } catch (Exception e) {
            log.error("load handler_cmd error-->" + requestClass);
            throw new RuntimeException(e.getMessage(), e);
        }
        HandlerFactory.addServerProcessor(this);
    }

    @Override
    public int getCmd() {
        return cmd;
    }

    @Override
    public void process(Channel channel, Packet packet) {
        if(packet.getMessageId() != cmd){
            return;
        }
        Request request = null;
        try {
            try {
                request = parser.parseFrom(packet.getContent());
            } catch (InvalidProtocolBufferException e) {
                log.error("协议[{}]数据反序列化异常",cmd,e);
                return;
            }
            Response response = doProcess(channel, request);
            if(response != null){
                packet.setContent(request.toByteArray());
                channel.writeAndFlush(packet);
            }
        }catch (Exception e){
            log.error("协议处理异常! channel:{},cmd:{},request:{}",channel,cmd,request);
        }
    }

    protected abstract Response doProcess(Channel channel,Request request);
}
